package com.landtool.lanbase.shipping;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import com.landtool.lanbase.constant.CacheConsts;
import com.landtool.lanbase.database.entity.WarnBlack;
import com.landtool.lanbase.database.service.WarnBlackService;
import com.landtool.lanbase.entity.ShipEntity;
import com.landtool.lanbase.utils.LocationUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 船只服务主要结构
 */
@Component
public class ShippingService {

    private static Logger log = LoggerFactory.getLogger(ShippingService.class);

    @Autowired
    private RedisTemplate <String, Object> redisTemplate;

    @Resource
    private WarnBlackService warnBlackService;

    /**
     * 分析船只数据，找到更新，丢失，新增船只
     */
    public HashMap <String, List <ShipEntity>> analyzeShipping() {
        HashMap <String, List <ShipEntity>> map = new HashMap <>(16);
        //大于1，就代表有新旧两组值
        String newKey = CacheConsts.openProvince + "_new";
        String oldKey = CacheConsts.openProvince + "_old";

        if (redisTemplate.hasKey(newKey) && redisTemplate.hasKey(oldKey)) {
            List <ShipEntity> newShipData = (List <ShipEntity>) redisTemplate.opsForValue().get(newKey);
            List <ShipEntity> oldShipData = (List <ShipEntity>) redisTemplate.opsForValue().get(oldKey);
            //对更新点进行操作
            List <ShipEntity> shipEntityUpdate = update(oldShipData, newShipData);
            List <ShipEntity> shipEntityDelete = delete(oldShipData, newShipData);
            List <ShipEntity> shipEntityAdd = add(oldShipData, newShipData);
            map.put("Update", shipEntityUpdate);
            map.put("Delete", shipEntityDelete);
            map.put("Add", shipEntityAdd);

            //将处理好的 字段提交到redis
            String resultKey = CacheConsts.openProvince + "_result";
            redisTemplate.opsForHash().putAll(resultKey, map);
            redisTemplate.expire(newKey, 500, TimeUnit.SECONDS);

        } else {
            log.info("analyzeShipping---无更新数据");
        }
        return map;
    }

    /**
     * 数据对比，找出新增，删除，更新的的点
     *
     * @param oldShipData
     * @param newShipData
     */
    public HashMap <String, List <ShipEntity>> dataCompare(List <ShipEntity> oldShipData, List <ShipEntity> newShipData) {
        List <ShipEntity> oldResult = new LinkedList <>(oldShipData);
        List <ShipEntity> newResult = new LinkedList <>(newShipData);
        List <ShipEntity> updataResult = new LinkedList <>();
        Set <Long> newset = new HashSet <>();
        Set <Long> oldset = new HashSet <>();

        for (ShipEntity shipEntity : newShipData) {
            newset.add(shipEntity.getTarget_id());
        }
        for (ShipEntity shipEntity : oldShipData) {
            oldset.add(shipEntity.getTarget_id());
        }

        Iterator <ShipEntity> oldLter = oldResult.listIterator();
        Iterator <ShipEntity> newLter = newResult.listIterator();
        while (oldLter.hasNext()) {
            ShipEntity shipEntity = oldLter.next();
            if (newset.contains(shipEntity.getTarget_id())) {
                updataResult.add(shipEntity);
            }
            if (newset.contains(shipEntity.getTarget_id())) {
                oldLter.remove();
            }
        }
        while (newLter.hasNext()) {
            ShipEntity shipEntity = newLter.next();
            if (oldset.contains(shipEntity.getTarget_id())) {
                newLter.remove();
            }
        }
        HashMap <String, List <ShipEntity>> map = new HashMap <>();
        map.put("updata", updataResult);
        map.put("delete", oldResult);
        map.put("add", newResult);
        return map;
    }

    /**
     * 计算更新船只
     *
     * @param oldShipList 上一批数据集合
     * @param newShipList 新的数据集合
     * @return
     */
    public List <ShipEntity> update(List <ShipEntity> oldShipList, List <ShipEntity> newShipList) {
        List <ShipEntity> list = new ArrayList <>();
        Integer pointer = 0;
        for (int i = 0; i < newShipList.size(); i++) {
            ShipEntity newShipEntity = newShipList.get(i);
            for (int j = pointer; j < oldShipList.size(); j++) {
                ShipEntity oldShipEntity = oldShipList.get(j);
                if (oldShipEntity.getTarget_id() > newShipEntity.getTarget_id()) {
                    break;
                }
                pointer++;
                if (oldShipEntity.getTarget_id().equals(newShipEntity.getTarget_id())) {
                    //对相等的Target_id进行操作
                    setMmsi(oldShipEntity, newShipEntity);
                    //判断更新船只条件
                    boolean isTimestamp = oldShipEntity.getTimestamp().equals(newShipEntity.getTimestamp());
                    boolean isLantitude = oldShipEntity.getLatitude().equals(newShipEntity.getLongitude());
                    boolean isLongitude = oldShipEntity.getLongitude().equals(newShipEntity.getLongitude());

                    if (!isTimestamp && !isLantitude && !isLongitude) {
                        //计算最大船长
                        setMaxLength(newShipEntity, oldShipEntity);
                        //计算持续时间
                        setDuration(oldShipEntity, newShipEntity);
                        //过滤数据
//                        setFilter(oldShipEntity, newShipEntity);

                        //判断目标持续时间小于1分钟
                        boolean speedJudge = newShipEntity.getSpeed() < 60;
                        if (speedJudge) {
                            list.add(newShipEntity);
                        }
                    }
                }
            }
        }
        return list;
    }


    /**
     * 设置条件过滤
     *
     * @param oldShipEntity
     * @param newShipEntity
     */
    private void setFilter(ShipEntity oldShipEntity, ShipEntity newShipEntity) {
        double oldLat = oldShipEntity.getLatitude();
        double oldLng = oldShipEntity.getLongitude();

        double newLat = newShipEntity.getLatitude();
        double newlng = newShipEntity.getLongitude();

        double distance = LocationUtils.getDistance(newLat, newlng, oldLat, oldLng);
//        System.out.println("距离" + distance + "米");

        //计算时间
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            Date newDate = format.parse(newShipEntity.getTimestamp());
            Date oldDate = format.parse(oldShipEntity.getTimestamp());
            Double oldDuration = oldShipEntity.getDuration();
            Double Duration = NumberUtil.div((newDate.getTime() - oldDate.getTime()), 60000);


        } catch (ParseException e) {
            e.printStackTrace();
            log.error("时间差计算错误");
        }
    }



    /**
     * 计算删除船只
     *
     * @param oldShipList 上一批数据集合
     * @param newShipList 新的数据集合
     * @return
     */
    private List <ShipEntity> delete(List <ShipEntity> oldShipList, List <ShipEntity> newShipList) {
        return getShipEntities(oldShipList, newShipList);
    }

    /**
     * 计算新增船只
     *
     * @param oldShipList 上一批数据集合
     * @param newShipList 新的数据集合
     * @return
     */
    public List <ShipEntity> add(List <ShipEntity> oldShipList, List <ShipEntity> newShipList) {
        List <ShipEntity> list = getShipEntities(newShipList, oldShipList);
        for (int i = 0; i < list.size(); i++) {
            ShipEntity shipEntity = list.get(i);
            if (shipEntity.getMmsi() != null && CacheConsts.WarnBlackList.size() > 0) {
                if (CacheConsts.WarnBlackList.containsKey(shipEntity.getMmsi().toString())) {
                    WarnBlack warnBlack = CacheConsts.WarnBlackList.get(shipEntity.getMmsi().toString());
                    warnBlack.setLasttime(new Date());
                    warnBlackService.update(warnBlack);
                }
            }

        }
        return list;
    }

    /**
     * 新增船只和删除船只 通用的代码
     *
     * @param ShipListA
     * @param ShipListB
     * @return
     */
    private List <ShipEntity> getShipEntities(List <ShipEntity> ShipListA, List <ShipEntity> ShipListB) {
        List <ShipEntity> list = new ArrayList <>();
        int pointer = 0;
        for (int i = 0; i < ShipListA.size(); i++) {
            ShipEntity shipEntityA = ShipListA.get(i);
            boolean bool = false;
            for (int j = pointer; j < ShipListB.size(); j++) {
                ShipEntity bShipEntity = ShipListB.get(j);
                if (shipEntityA.getTarget_id().equals(bShipEntity.getTarget_id())) {
                    bool = true;
                    pointer++;
                    break;
                } else if (shipEntityA.getTarget_id() < bShipEntity.getTarget_id()) {
                    break;
                }
            }
            if (!bool) {
                list.add(shipEntityA);
            }
        }
        return list;
    }


    /**
     * 计算持续时间
     *
     * @param oldShipEntity 上一批数据
     * @param newShipEntity 新的数据
     */
    private void setDuration(ShipEntity oldShipEntity, ShipEntity newShipEntity) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            Date newDate = format.parse(newShipEntity.getTimestamp());
            Date oldDate = format.parse(oldShipEntity.getTimestamp());
            Double oldDuration = oldShipEntity.getDuration();
            Double Duration = NumberUtil.div((newDate.getTime() - oldDate.getTime()), 60000);
            Double newDuration = NumberUtil.add(Duration, oldDuration);
            newShipEntity.setDuration(Double.valueOf(NumberUtil.roundStr(newDuration, 2)));
        } catch (ParseException e) {
            e.printStackTrace();
            log.error("时间差计算错误");
        }
    }

    /**
     * 计算最大船长
     *
     * @param oldShipEntity 上一批数据
     * @param newShipEntity 新的数据
     */
    private void setMaxLength(ShipEntity newShipEntity, ShipEntity oldShipEntity) {
        Double maxLength = newShipEntity.getMaxlength() > oldShipEntity.getMaxlength() ? newShipEntity.getMaxlength() : oldShipEntity.getMaxlength();
        newShipEntity.setMaxlength(maxLength);
    }

    /**
     * 当targetid相等时，设置mmsi
     *
     * @param oldShipEntity 上一批数据
     * @param newShipEntity 新的数据
     */
    private void setMmsi(ShipEntity oldShipEntity, ShipEntity newShipEntity) {
        if (newShipEntity.getMmsi() != null) {
            if (newShipEntity.getMmsi() == 0 && oldShipEntity.getShip_class() != null) {
                if (oldShipEntity.getShip_class() == 1) {
                    newShipEntity.setMmsi(null);
                    newShipEntity.setShip_class(1);
                    if (newShipEntity.getAislength() != null) {
                        newShipEntity.setAislength(null);
                    }
                }
            }
        }

        if (oldShipEntity.getMmsi() != null && newShipEntity.getMmsi() != null) {
            if (oldShipEntity.getMmsi() != 0 && newShipEntity.getMmsi() != 0) {
                newShipEntity.setMmsi(oldShipEntity.getMmsi());
            }
        }

    }


}
